package org.apache.solr.ocean.util;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

public class Range<T> {
	private final T lowerVal;
	private final T upperVal;
	private final boolean includeLower;
	private final boolean includeUpper;
	private int hashCode;

	public Range(T lowerVal, boolean includeLower, T upperVal, boolean includeUpper) {
		this.lowerVal = lowerVal;
		this.upperVal = upperVal;
		assert lowerVal != null || upperVal != null;
		this.includeLower = includeLower;
		this.includeUpper = includeUpper;
		HashCodeBuilder builder = new HashCodeBuilder(61, 781);
		builder.append(lowerVal);
		builder.append(upperVal);
		builder.append(includeLower);
		builder.append(includeUpper);
		hashCode = builder.toHashCode();
	}
  
	public boolean equals(Object object) {
		if (!(object instanceof Range))
			return false;
		if (object == null)
			return false;
		Range other = (Range) object;
		EqualsBuilder equalsBuilder = new EqualsBuilder();
		equalsBuilder.append(lowerVal, other.lowerVal);
		equalsBuilder.append(upperVal, other.upperVal);
		equalsBuilder.append(includeLower, other.includeLower);
		equalsBuilder.append(includeUpper, other.includeUpper);
		return equalsBuilder.isEquals(); 
	}
	
	public boolean isType(Class clazz) {
		if (lowerVal != null) {
			return lowerVal.getClass().isAssignableFrom(clazz);
		} else {
			return upperVal.getClass().isAssignableFrom(clazz);
		}
	}
	
	public String toString() {
		StringBuilder buffer = new StringBuilder();
		buffer.append(includeLower ? '[' : '{');
		buffer.append(lowerVal != null ? lowerVal : "*");
		buffer.append(" TO ");
		buffer.append(upperVal != null ? upperVal : "*");
		buffer.append(includeUpper ? ']' : '}');
		return buffer.toString();
	}
	
	public T getLowerVal() {
		return lowerVal;
	}

	public T getUpperVal() {
		return upperVal;
	}

	public boolean isIncludeLower() {
		return includeLower;
	}

	public boolean isIncludeUpper() {
		return includeUpper;
	}
}
